<template>
  <div class="preview-wrap">
    <div class="preview">
      <div ref="container" class="preview-body">
        <v-stage
          v-if="init"
          ref="stage"
          :config="{ width, height }"
          @dragstart="handleDragstart"
          @dragend="handleDragend"
          @wheel="handleWheel"
          @mousedown="handleStageMouseDown"
          @touchstart="handleStageMouseDown"
          @mousemove="handleStageMouseMove"
          @mouseup="handleStageMouseUp"
        >
          <v-layer ref="layer">
            <v-group :config="{ width, height, x, y }">
              <components
                :components="components"
                @transformend="handleTransformEnd"
              />
              <Metrics :configs="components" />
            </v-group>
            <v-transformer
              ref="transformer"
              :config="{
                rotateEnabled: false,
              }"
            />
          </v-layer>
        </v-stage>
      </div>
    </div>
  </div>
</template>

<script>
import { mapMutations, mapState, mapGetters } from 'vuex'
import components from './components'
import Metrics from './Metrics'
export default {
  name: 'Preview',
  components: { components, Metrics },
  data() {
    return {
      list: [],
      dragItemId: null,
      width: 0,
      height: 0,
      x: 200,
      y: 100,
      init: false,
    }
  },
  computed: {
    ...mapState(['components', 'current']),
    ...mapGetters(['getSection', 'selectedSection']),
  },
  mounted() {
    const { container } = this.$refs
    const { offsetWidth, offsetHeight } = container
    this.width = offsetWidth
    this.height = offsetHeight
    this.init = true
  },
  watch: {
    current(newVal, oldVal) {
      if (!newVal && this.selectedShapeName) {
        this.selectedShapeName = ''
        this.updateTransformer()
      }
    },
  },
  methods: {
    ...mapMutations(['currentComponent', 'updateProps']),
    handleDragstart(e) {
      // save drag element:
      this.dragItemId = e.target.id()
      // move current element to the top:
      // const item = this.list.find((i) => i.id === this.dragItemId)
      // const index = this.list.indexOf(item)
      // this.list.splice(index, 1)
      // this.list.push(item)
    },

    handleDragend(e) {
      this.dragItemId = null
    },
    handleWheel(event) {
      event.evt.preventDefault()
      const scaleBy = 1.1
      const stage = event.target.getStage()
      const oldScale = stage.scaleX()
      const mousePointTo = {
        x: stage.getPointerPosition().x / oldScale - stage.x() / oldScale,
        y: stage.getPointerPosition().y / oldScale - stage.y() / oldScale,
      }
      const newScale =
        event.evt.deltaY > 0 ? oldScale * scaleBy : oldScale / scaleBy
      stage.scale({ x: newScale, y: newScale })
      const newPos = {
        x:
          -(mousePointTo.x - stage.getPointerPosition().x / newScale) *
          newScale,
        y:
          -(mousePointTo.y - stage.getPointerPosition().y / newScale) *
          newScale,
      }
      stage.position(newPos)
      stage.batchDraw()
    },

    handleTransformEnd(e) {
      // shape is transformed, let us save new attrs back to the node
      // find element in our state
      const rect = {
        ...this.selectedSection.props,
      }
      // update the state
      rect.x = e.target.x()
      rect.y = e.target.y()
      rect.width = Math.ceil(e.target.scaleX() * rect.width)
      rect.height = Math.ceil(e.target.scaleY() * rect.height)
      const transformerNode = this.$refs.transformer.getNode()
      const stage = transformerNode.getStage()
      const { selectedShapeName } = this

      const selectedNode = stage.findOne('#' + selectedShapeName).parent
      selectedNode.scaleX(1)
      selectedNode.scaleY(1)

      const position = selectedNode.position()
      rect.x = position.x
      rect.y = position.y

      console.log(JSON.stringify(rect), position, '===============')
      this.updateProps(rect)
      // todo update to store
      this.$nextTick(() => transformerNode.forceUpdate())
    },
    handleStageMouseMove(e) {
      if (!this.moving) {
        return
      }
      e.evt.preventDefault()
      this.x += e.evt.movementX
      this.y += e.evt.movementY
    },
    handleStageMouseUp() {
      this.moving = false
    },
    handleStageMouseDown(e) {
      // clicked on stage - clear selection
      if (e.target === e.target.getStage()) {
        this.selectedShapeName = ''
        this.currentComponent('')
        this.updateTransformer()
        this.moving = true
        return
      }

      // clicked on transformer - do nothing
      const clickedOnTransformer =
        e.target.getParent().className === 'Transformer'
      if (clickedOnTransformer) {
        return
      }
      this.moving = true

      // find clicked rect by its name
      const id = e.target.id()
      const rect = this.getSection(id)
      if (rect) {
        this.selectedShapeName = id
        this.currentComponent(id)
      } else {
        this.selectedShapeName = ''
        this.currentComponent('')
      }
      this.updateTransformer()
    },
    updateTransformer() {
      // here we need to manually attach or detach Transformer node
      const transformerNode = this.$refs.transformer.getNode()
      const stage = transformerNode.getStage()
      const { selectedShapeName } = this

      if (!selectedShapeName) {
        transformerNode.nodes([])
        return
      }

      const selectedNode = stage.findOne('#' + selectedShapeName)
      const group = selectedNode && selectedNode.getParent()
      // do nothing if selected node is already attached
      if (group && group === transformerNode.node()) {
        return
      }

      if (group) {
        // attach to another node
        transformerNode.nodes([group])
      } else {
        // remove transformer
        transformerNode.nodes([])
      }
    },
  },
}
</script>

<style>
.preview-wrap {
  flex: 1;
  height: calc(100vh - 40px);
  overflow-y: auto;
  overflow-x: hidden;
  background-color: #f7f8fa;
  display: -ms-flexbox;
  display: flex;
  -ms-flex-pack: center;
  justify-content: center;
  -webkit-user-select: none;
  -ms-user-select: none;
  user-select: none;
}

.preview-wrap .preview {
  width: 100%;
}

.preview-body {
  height: 100%;
}

.preview-wrap .preview .preview-head {
  height: 64px;

  background-repeat: no-repeat;
  background-size: cover;
  background-position: 50%;
  position: relative;
  box-shadow: 0 0 14px 0 rgba(0, 0, 0, 0.1);
}

.preview-wrap .preview .preview-head .preview-header-title {
  width: 180px;
  margin: 0 auto;
  height: 34px;
  text-align: center;
  padding-top: 30px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  box-sizing: content-box;
}

.preview-wrap::-webkit-scrollbar {
  -webkit-appearance: none;
  width: 3px;
  background-color: #f5f5f5;
}

.preview-wrap::-webkit-scrollbar-thumb {
  background: rgba(0, 0, 0, 0.3);
}
</style>
